/////////////////  comments  /////////////////  

#include <vector>
#include "combined.h"
#include "command.h"
#include "commandTable.h"
#include "definitions.h"
#include "log.h"
#include "stringutil.h"
#include "timestamp.h"
#include "world.h"

// Command definitions for commands beginning with the letters N through P
// (Keep in alphabetical order... it's MUCH easier)
CmdNorth::CmdNorth( void ) {
	setName( "north" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "north east south west up down movement" );
	addSyntax( "syntax: north     {CMove north" );
}

bool CmdNorth::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string fromMessage;
	std::string toMessage;
	Exit* in = character->getRoom()->getExit( NORTH );

	if ( !in->getThere() ) {
		buf << "There is no exit that way.";
		character->Send( buf );
		return false;
	} else if ( in->getDoor() && !in->getOpen() ) {
		buf << "That door is closed.";
		character->Send( buf );
		return false;
	} else {
		Room* from = character->getRoom();
		Room* to = NULL;
		if ( ( to = World::Instance().getRoom( in->getPoint() ) ) == NULL ) {
			character->Send( "You can't go there." );
			std::string message = "Exit inconsistency: ";
			message << from->getVnum() << " north to " << in->getPoint();
			log( message, WORLD );
			return false;
		}

		fromMessage << character->getName() << " has left to the north.";
		toMessage << character->getName() << " has arrived from the south.";

		from->drop( character );
		from->send( character->getName() + " has left to the north." );
		to->send( character->getName() + " has arrived from the south." );
		to->add( character );
		character->setRoom( to );

		// Force the "look" Command...
		std::string empty;
		CmdLook commandLook;
		commandLook.execute( character, empty );
	}

	return true;
}

/*CmdNotes::CmdNotes( void ) {
	setName( "notes" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
}

bool CmdNotes::execute( Character* character, const std::string& args ) {
	std::string buf;

	return true;
}*/

/*CmdOedit::CmdOedit( void ) {
	setName( "oedit" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
}

bool CmdOedit::execute( Character* character, const std::string& args ) {

	return false;
}

CmdOlist::CmdOlist( void ) {
	setName( "olist" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
}

bool CmdOlist::execute( Character* character, const std::string& args ) {

	return false;
}

CmdOload::CmdOload( void ) {
	setName( "oload" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( true );
}

bool CmdOload::execute( Character* character, const std::string& args ) {

	return false;
}*/

CmdOmninet::CmdOmninet( void ) {
	setName( "omninet" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "omninet omniset immortal" );
	addSyntax( "syntax: omninet             {CDisplays omninet status" );
	addSyntax( "        omninet <on|off>    {CToggles omninet status" );
	addSyntax( "        omninet <option>    {CToggles omninet option" );
	addHelp( "Omninet is an immortal channel that displays many various system and world" );
	addHelp( "messages, such as who's loggin in/out, when ticks and autosaves occur, as" );
	addHelp( "well as a notification when certain commands are used, who used them, and" );
	addHelp( "what their syntax was." );
}

bool CmdOmninet::execute( Character* character, const std::string& args ) {
	std::string buf;

	if ( args == "off" ) {
		character->setOmninet( false );
		buf << "Omninet is now {roff{x.";
	} else if ( args == "on" ) {
		character->setOmninet( true );
		buf << "Omninet is now {Gon{x.";
	} else {
		buf << "Omninet ";
		if ( character->getOmninet() )
			buf << "{Gon";
		else
			buf << "{roff";
		buf << "{x.";
	}

	character->Send( buf );

	return true;
}

CmdOmniset::CmdOmniset( void ) {
	setName( "omniset" );
	setLevel( HEAD );
	setEnabled( true );
	setOmniset( true );
	setTags( "omniset omninet immortal" );
	addSyntax( "syntax: omniset               {CDisplays which commands are omniset" );
	addSyntax( "        omniset <command>     {CToggles omniset status of given command" );
	addHelp( "Omniset is a per-command option that controls whether or not the command," );
	addHelp( "when used, sends a message through the Omninet." );
}

bool CmdOmniset::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string temp;
	unsigned i=0;

	// HEAD Commands...
	if ( character->getLevel() >= HEAD ) {
		buf << "\n\r\t{cHead commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = CommandTable::Instance().getCommands().begin(); it != CommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == HEAD && (*it)->getOmniset() ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// GOD Commands...
	if ( character->getLevel() >= GOD ) {
		i = 0;
		buf << "\n\r\t{cGod commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = CommandTable::Instance().getCommands().begin(); it != CommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == GOD && (*it)->getOmniset() ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// BUILDER Commands...
	if ( character->getLevel() >= BUILDER ) {
		i = 0;
		buf << "\n\r\t{cBuilder commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = CommandTable::Instance().getCommands().begin(); it != CommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == BUILDER && (*it)->getOmniset() ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// KING Commands...
	if ( character->getLevel() >= KING ) {
		i = 0;
		buf << "\n\r\t{cKing commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = CommandTable::Instance().getCommands().begin(); it != CommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == KING && (*it)->getOmniset() ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// LORD Commands...
	if ( character->getLevel() >= LORD ) {
		i = 0;
		buf << "\n\r\t{cLord commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = CommandTable::Instance().getCommands().begin(); it != CommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == LORD && (*it)->getOmniset() ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// Regular Commands...
	buf << "\n\r\t{c-- Commands --{x \n\r";
	i = 0;
	for ( std::vector< Command* >::iterator it = CommandTable::Instance().getCommands().begin(); it != CommandTable::Instance().getCommands().end(); ++it ) {
		if ( (*it)->getLevel() == 1 && (*it)->getOmniset() ) {
			if ( i % 6 == 0 ) {
				if ( i )
					buf << "\n\r";
				buf << "  ";
			}
			if ( (*it)->getEnabled() )
				buf << format( 12, (*it)->getName(), temp );
			else
				buf << format( 12, (*it)->getName(), temp, 'w' );
			i++;
		}
	}

	character->Send( buf );

	return true;
}

CmdOpen::CmdOpen( void ) {
	setName( "open" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "open close door container" );
	addSyntax( "syntax: open <door>         {COpens the given (unlocked) door" );
	addSyntax( "        open <container>    {COpens the given (unlocked) container" );
}

bool CmdOpen::execute( Character* character, const std::string& args ) {
	std::string buf;

	if ( args.empty() ) {
		character->Send( "Which door do you wish to open?" );
		return true;
	}

	if ( strcmp( args.c_str(), "north" ) == 0 || strcmp( args.c_str(), "n" ) == 0 ) {
		if ( !character->getRoom()->getExit( NORTH )->getThere() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( !character->getRoom()->getExit( NORTH )->getDoor() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( character->getRoom()->getExit( NORTH )->getOpen() ) {
			character->Send( "That door is already open." );
			return true;
		}
		if ( character->getRoom()->getExit( NORTH )->getLocked() ) {
			character->Send( "That door is locked." );
			return true;
		}
		character->getRoom()->getExit( NORTH )->setOpen( true );
		World::Instance().getRoom( character->getRoom()->getExit( NORTH )->getPoint() )->getExit( SOUTH )->setOpen( true );
		character->Send( "You have opened the door." );
		return true;
	}
	if ( strcmp( args.c_str(), "east" ) == 0 || strcmp( args.c_str(), "e" ) == 0 ) {
		if ( !character->getRoom()->getExit( EAST )->getThere() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( !character->getRoom()->getExit( EAST )->getDoor() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( character->getRoom()->getExit( EAST )->getOpen() ) {
			character->Send( "That door is already open." );
			return true;
		}
		if ( character->getRoom()->getExit( EAST )->getLocked() ) {
			character->Send( "That door is locked." );
			return true;
		}
		character->getRoom()->getExit( EAST )->setOpen( true );
		World::Instance().getRoom( character->getRoom()->getExit( EAST )->getPoint() )->getExit( WEST )->setOpen( true );
		character->Send( "You have opened the door." );
		return true;
	}
	if ( strcmp( args.c_str(), "south" ) == 0 || strcmp( args.c_str(), "s" ) == 0 ) {
		if ( !character->getRoom()->getExit( SOUTH )->getThere() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( !character->getRoom()->getExit( SOUTH )->getDoor() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( character->getRoom()->getExit( SOUTH )->getOpen() ) {
			character->Send( "That door is already open." );
			return true;
		}
		if ( character->getRoom()->getExit( SOUTH )->getLocked() ) {
			character->Send( "That door is locked." );
			return true;
		}
		character->getRoom()->getExit( SOUTH )->setOpen( true );
		World::Instance().getRoom( character->getRoom()->getExit( SOUTH )->getPoint() )->getExit( NORTH )->setOpen( true );
		character->Send( "You have opened the door." );
		return true;
	}
	if ( strcmp( args.c_str(), "west" ) == 0 || strcmp( args.c_str(), "w" ) == 0 ) {
		if ( !character->getRoom()->getExit( WEST )->getThere() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( !character->getRoom()->getExit( WEST )->getDoor() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( character->getRoom()->getExit( WEST )->getOpen() ) {
			character->Send( "That door is already open." );
			return true;
		}
		if ( character->getRoom()->getExit( WEST )->getLocked() ) {
			character->Send( "That door is locked." );
			return true;
		}
		character->getRoom()->getExit( WEST )->setOpen( true );
		World::Instance().getRoom( character->getRoom()->getExit( WEST )->getPoint() )->getExit( EAST )->setOpen( true );
		character->Send( "You have opened the door." );
		return true;
	}
	if ( strcmp( args.c_str(), "up" ) == 0 || strcmp( args.c_str(), "u" ) == 0 ) {
		if ( !character->getRoom()->getExit( UP )->getThere() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( !character->getRoom()->getExit( UP )->getDoor() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( character->getRoom()->getExit( UP )->getOpen() ) {
			character->Send( "That door is already open." );
			return true;
		}
		if ( character->getRoom()->getExit( UP )->getLocked() ) {
			character->Send( "That door is locked." );
			return true;
		}
		character->getRoom()->getExit( UP )->setOpen( true );
		World::Instance().getRoom( character->getRoom()->getExit( UP )->getPoint() )->getExit( DOWN )->setOpen( true );
		character->Send( "You have opened the door." );
		return true;
	}
	if ( strcmp( args.c_str(), "down" ) == 0 || strcmp( args.c_str(), "d" ) == 0 ) {
		if ( !character->getRoom()->getExit( DOWN )->getThere() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( !character->getRoom()->getExit( DOWN )->getDoor() ) {
			character->Send( "There is no door that way." );
			return true;
		}
		if ( character->getRoom()->getExit( DOWN )->getOpen() ) {
			character->Send( "That door is already open." );
			return true;
		}
		if ( character->getRoom()->getExit( DOWN )->getLocked() ) {
			character->Send( "That door is locked." );
			return true;
		}
		character->getRoom()->getExit( DOWN )->setOpen( true );
		World::Instance().getRoom( character->getRoom()->getExit( DOWN )->getPoint() )->getExit( UP )->setOpen( true );
		character->Send( "You have opened the door." );
		return true;
	}
	return true;
}

CmdPassword::CmdPassword( void ) {
	setName( "password" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "password security" );
	addSyntax( "syntax: <old password> <new password> <new password>  {CChange your password" );
	addHelp( "\"password\" asks for your new password twice just as a confirmation." );
}

bool CmdPassword::execute( Character* character, const std::string& args ) {
	std::string oldP;
	std::string newP;
	std::string confirmP;

	split( args, oldP, newP, confirmP );

	if ( oldP.empty() || newP.empty() || confirmP.empty() ) {
		character->Send( "syntax: <old password> <new password> <confirm password>" );
		return false;
	}

	if ( oldP != character->getPassword() ) {
		character->Send( "Incorrect password." );
		return false;
	}
	if ( newP != confirmP ) {
		character->Send( "Passwords do not match." );
		return false;
	}

	character->setPassword( newP.c_str() );
	character->Send( "Password changed." );

	return true;
}

CmdPedit::CmdPedit( void ) {
	setName( "pedit" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( true );
	setTags( "pedit immortal" );
	addSyntax( "syntax: pedit <target>    {COpens an editor for the given character" );
}

bool CmdPedit::execute( Character* character, const std::string& args ) {
	std::string name = trim( args );
	Character* p = NULL;

	if ( ( p = World::Instance().getCharacter( name ) ) == NULL ) {
		character->Send( "Target not found." );
		return false;
	}

	character->setCharacter( p );
	character->setStatus( PEDIT );
	character->Send( "Welcome to the Symphony Edit Mode (SEM) for Players!" );

	return true;
}

CmdPoofin::CmdPoofin( void ) {
	setName( "poofin" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "poofin poofout goto" );
	addSyntax( "syntax: poofin              {CDisplays your current poofin" );
	addSyntax( "        poofin <string>     {CChanges your poofin to the given string" );
	addSyntax( "        poofin -            {CRemove your poofin" );
	addHelp( "If set, your poofin is a string that will be displayed to everyone in" );
	addHelp( "the room you've just entered when using the \"goto\" command." );
}

bool CmdPoofin::execute( Character* character, const std::string& args ) {
	std::string poof;
	std::string empty_string;

	if ( args.empty() ) {
		character->Send( " >> \"poofin\" changes the text displayed to other characters when you enter a room via 'goto'.\n\r\n\rsyntax: poofin <message> (to change poofin)\n\r        poofin -         (to remove poofin)" );
		return false;
	}
	if ( args == "-" ) {
		character->setPoofin( empty_string );
		character->Send( "Your poofin has been disabled." );
		return true;
	}

	poof = args;
	poof = trim( poof );
	character->setPoofin( poof );
	character->Send( "Your poofin has been set to: " + poof );

	return true;
}

CmdPoofout::CmdPoofout( void ) {
	setName( "poofout" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "poofout poofin goto" );
	addSyntax( "syntax: poofout              {CDisplays your current poofout" );
	addSyntax( "        poofout <string>     {CChanges your poofout to the given string" );
	addSyntax( "        poofout -            {CRemove your poofout" );
	addHelp( "If set, your poofout is a string that will be displayed to everyone in" );
	addHelp( "the room you've just exited when using the \"goto\" command." );
}

bool CmdPoofout::execute( Character* character, const std::string& args ) {
	std::string poof;
	std::string empty_string;

	if ( args.empty() ) {
		character->Send( " >> \"poofout\" changes the text displayed to other characters when you leave a room via 'goto'.\n\r\n\rsyntax: poofout <message> (to change poofout)\n\r        poofout -         (to remove poofout)" );
		return false;
	}
	if ( args == "-" ) {
		character->setPoofout( empty_string );
		character->Send( "Your poofout has been disabled." );
		return true;
	}

	poof = args;
	poof = trim( poof );
	character->setPoofout( poof );
	character->Send( "Your poofout has been set to: " + poof );

	return true;
}

CmdPoofs::CmdPoofs( void ) {
	setName( "poofs" );
	setLevel( BUILDER );
	setEnabled( true );
	setOmniset( false );
	setTags( "poofs poofin poofout" );
	addSyntax( "syntax: poofs     {CDisplays your current poofin and poofout" );
}

bool CmdPoofs::execute( Character* character, const std::string& args ) {
	std::string buf;

	if ( character->getPoofin().empty() )
		buf << "poofin: {wnot set{x";
	else
		buf << "poofin: " << character->getPoofin();
	buf << "\n\r";
	if ( character->getPoofout().empty() )
		buf << "poofout: {wnot set{x";
	else
		buf << "poofout: " << character->getPoofout();

	character->Send( buf );

	return true;
}

CmdPromote::CmdPromote( void ) {
	setName( "promote" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( true );
	setTags( "promote demote" );
	addSyntax( "syntax: promote <target> <level>  {CPromotes target character to the given level" );
}

bool CmdPromote::execute( Character* character, const std::string& args ) {
	std::string name;
	std::string sLevel;
	std::string charBuf, targBuf;
	unsigned level = 0;
	Character* target = NULL;

	split( args, name, sLevel );

	if ( name.empty() || sLevel.empty() ) {
		character->Send( " >> \"promote\" increases a characters' level.\n\rsyntax: promote <character name> <level>" );
		return false;
	}

	level = atoi( sLevel.c_str() );
	if ( ( target = World::Instance().getCharacter( name ) ) == NULL ) {
		character->Send( "That target cannot be found." );
		return false;
	}

	if ( target->getLevel() >= level ) {
		character->Send( "That wouldn't be a promotion." );
		return false;
	}

	if ( character->getLevel() <= target->getLevel() + 2 || character->getLevel() <= level + 2 ) {
		character->Send( "You do not have permission to do that." );
		return false;
	}

	target->setLevel( level );
	charBuf << "You have promoted " << target->getName() << " to level " << target->getLevel() << "!";
	targBuf << character->getName() << " has {Gpromoted{x you to level {W" << target->getLevel() << "{x!";
	character->Send( charBuf );
	target->Send( targBuf );

	return true;
}

CmdPrompt::CmdPrompt( ) {
	setName( "prompt" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "prompt" );
    addSyntax( "syntax: prompt <prompt> {CChanges your current prompt" );
}

bool CmdPrompt::execute( Character* character, const std::string& args ) {
    std::string buf;
    
    if ( args.empty() ) {
		buf << "current prompt: " << character->getPrompt() << "{x\n\r";
		buf << "{cOptions{x (an option is % followed by one of the following characters)\n\r";
		buf << "\tH\tmax hp\n\r";
		buf << "\th\tcurrent hp\n\r";
		buf << "\tM\tmax mana\n\r";
		buf << "\tm\tcurrent mana\n\r";
		buf << "\tV\tmax movement\n\r";
		buf << "\tv\tcurrent movement\n\r";
		buf << "\tG\tgold held\n\r";
		buf << "\tg\tgold in bank\n\r";
		buf << "\tS\tsilver held\n\r";
		buf << "\ts\tsilver in bank\n\r";
		if ( character->getLevel() >= BUILDER ) {
			buf << "{cImmortal Options{x\n\r";
			buf << "\tr\tcurrent room vnum\n\r";
		}
    	character->Send( buf );
    	return false;
    }

	character->setPrompt( args );
	buf << "Prompt reset to " << character->formatPrompt() << "{x";
	character->Send( buf );

	return true;
}
